package com.yuan.springcloud.user.aspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.yuan.springcloud.common.utils.HttpContextUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * Controller层接口切面，实现自动记录日志
 *
 * @author YouYuan
 * @date 2020/8/25 20:43
 */
@Aspect
@Component
@Slf4j
public class ControllerLogAspect {

    private static final ThreadLocal<Long> START_TIME = new ThreadLocal<>();

    public static void setStartTime(Long data) {
        START_TIME.set(data);
    }

    public static Long getStartTime() {
        return START_TIME.get();
    }

    public static void removeStartTime() {
        START_TIME.remove();
    }

    @Pointcut("execution(public * com.yuan..controller.*Controller.*(..))")
    public void apiLog() {
    }

    @Before("apiLog()")
    public void doBefore(JoinPoint joinPoint) {
        if (log.isInfoEnabled()) {
            HttpServletRequest request = HttpContextUtil.getRequest();
            String method = null;
            String servletPath = null;
            if (request != null) {
                method = request.getMethod();
                servletPath = request.getServletPath();
            }
            START_TIME.set(System.currentTimeMillis());
            String classAndMethod = getClassAndMethod(joinPoint);
            Object[] args = joinPoint.getArgs();
            log.info("path:{}, mapping:{}, Args->:{}", servletPath, classAndMethod, argsToStr(args));
        }
    }

    @AfterReturning(returning = "rs", pointcut = "apiLog()")
    public void doAfter(JoinPoint joinPoint, Object rs) {
        if (log.isInfoEnabled()) {
            long usingTime = (System.currentTimeMillis() - START_TIME.get());
            String classAndMethod = getClassAndMethod(joinPoint);
            log.info("[{} Done] Using:{}ms Return->:{}", classAndMethod, usingTime, JSON.toJSONString(rs));
        }
    }


    private String getClassAndMethod(JoinPoint joinPoint) {
        return joinPoint.getSignature().getDeclaringType().getSimpleName() +
                "." + joinPoint.getSignature().getName();
    }

    public static String argsToStr(Object[] args) {
        try {
            StringBuilder sb = new StringBuilder();
            if (args != null && args.length > 0) {
                for (int i = 0; i < args.length; i++) {
                    if (i != 0) {
                        sb.append(" |,| ");
                    }
//                    sb.append("args[").append(i).append("]:");
                    if (args[i] == null) {
                        sb.append("null");
                    } else {
                        if (args[i].getClass().equals(byte[].class)) {
                            byte[] bb = (byte[]) args[i];
                            sb.append("bytes[").append(bb == null ? "0" : bb.length).append("]");
                        } else if (args[i] instanceof MultipartFile) {
                            sb.append("MultipartFile");
                        } else if (args[i] instanceof MultipartFile[]) {
                            sb.append("MultipartFileArr");
                        } else if (args[i] instanceof HttpServletRequest) {
                            sb.append("HttpServletRequest");
                        } else if (args[i] instanceof HttpServletResponse) {
                            sb.append("HttpServletResponse");
                        } else if (args[i] instanceof HttpSession) {
                            sb.append("HttpSession");
                        } else {
                            sb.append(JSON.toJSONString(args[i]));
                        }
                    }
                }
            } else {
                sb.append("null");
            }
            return sb.toString();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return null;
        }

    }
}
